package com.fly.studio.home.app.arrange.core;

import com.fly.studio.home.app.arrange.base.BaseWorker;
import com.fly.studio.home.app.component.BaseContext;
import com.fly.studio.home.app.component.ServerRelation;
import com.fly.studio.home.app.service.ServerService;
import com.fly.studio.home.app.arrange.base.WorkerFactory;
import com.jd.platform.async.executor.Async;
import com.jd.platform.async.wrapper.WorkerWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;

/**
 * Floor Arrange
 *
 * @author fuliying3
 * @date 2022/08/23 09:08:00
 */
@Slf4j
@Component
public class ComponentArrange {

    @Resource(name = "homePageThreadPool")
    private ExecutorService executorService;
    @Resource
    private WorkerFactory workerFactory;
    @Resource
    private ServerService serverService;
    @Value("${async-tool.worker-timeout}")
    private long timeout;

    /**
     * 执行编排
     *
     * @param baseContext {@link BaseContext}
     */
    public void arrange(BaseContext baseContext) {
        try {
            WorkerWrapper<BaseContext, BaseContext>[] rootWorkWrappers = doArrange(baseContext);
            Async.beginWork(timeout, executorService, rootWorkWrappers);
        } catch (Exception e) {
            log.error("FloorArrange arrange Exception", e);
        }
    }

    /**
     * 获取
     *
     * @param baseContext {@link BaseContext}
     * @return WorkerWrapper
     */
    private WorkerWrapper<BaseContext, BaseContext>[] doArrange(BaseContext baseContext) {
        List<ServerRelation> serverList = serverService.serverList().stream()
                .sorted(Comparator.comparingInt(ServerRelation::getSerialNumber))
                .collect(Collectors.toList());
        int rootSize = (int) serverList.stream().filter(server -> server.getLayers().equals(1)).count();
        WorkerWrapper<BaseContext, BaseContext>[] rootWorkWrappers = new WorkerWrapper[rootSize];
        WorkerWrapper<BaseContext, BaseContext>[] workWrappers = new WorkerWrapper[serverList.size()];
        for (int i = 0; i < serverList.size(); i++) {
            ServerRelation server = serverList.get(i);
            BaseWorker baseWorker = workerFactory.getHandler(server.getClassName());
            if (i < rootSize) {
                rootWorkWrappers[i] = new WorkerWrapper.Builder<BaseContext, BaseContext>()
                        .worker(baseWorker)
                        .callback(baseWorker)
                        .param(baseContext)
                        .build();
                workWrappers[i] = rootWorkWrappers[i];
            } else {
                List<Integer> dependsSerialNumber = server.getDependsSerialNumber();
                if (CollectionUtils.isEmpty(dependsSerialNumber)) {
                    workWrappers[i] = new WorkerWrapper.Builder<BaseContext, BaseContext>()
                            .worker(baseWorker)
                            .callback(baseWorker)
                            .param(baseContext)
                            .build();
                } else {
                    WorkerWrapper<BaseContext, BaseContext>[] depends = new WorkerWrapper[dependsSerialNumber.size()];
                    for (int j = 0; j < dependsSerialNumber.size(); j++) {
                        depends[j] = workWrappers[dependsSerialNumber.get(j) - 1];
                    }
                    workWrappers[i] = new WorkerWrapper.Builder<BaseContext, BaseContext>()
                            .worker(baseWorker)
                            .callback(baseWorker)
                            .depend(depends)
                            .param(baseContext)
                            .build();
                }
            }
        }
        return rootWorkWrappers;
    }
}
